{"cells":[{"attachments":{},"cell_type":"markdown","metadata":{"id":"11n5gndbRzoY"},"source":["# Other collections - Dictionaries and Sets\n"]},{"attachments":{},"cell_type":"markdown","metadata":{"id":"AIFsv_RZ1iV0"},"source":["\n"," \n"," \n","
\n"," \"Open\n"," \n"," \n","
"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["We’ve discussed three built-in sequence collections — `strings`, `lists` and `tuples`. Now, we consider the built-in non-sequence collections — `dictionaries` and `sets`. A `dictionary` is an unordered collection which stores ***key–value*** pairs that map immutable keys to values, just as a conventional dictionary maps words to definitions. A `set` is an unordered collection of unique immutable elements."]},{"cell_type":"markdown","metadata":{"id":"UVyscPC3mYeo"},"source":["## Dictionaries"]},{"attachments":{},"cell_type":"markdown","metadata":{"id":"MOGo5JaVmdnJ"},"source":["Like a `list`, a `dictionary` is a mutable collection of many values, but more general. In a `list`, the index positions have to be integers; in a `dictionary`, the indices can be any immutable data type. You can think of a dictionary as a mapping between a set of indices (which are called ***keys***) and a set of ***values***. Each key maps to a value. The association of a key and a value is called a ***key-value*** pair or sometimes an ***item***.\n","\n","A `dictionary`’s keys must be immutable (such as `strings`, `integers` or `tuples`) and unique (that is, no duplicates). However, multiple keys can have the same value."]},{"attachments":{},"cell_type":"markdown","metadata":{"id":"42QE-OUnptIL"},"source":["
\n","
source: https://pynative.com/python-dictionaries/
"]},{"attachments":{},"cell_type":"markdown","metadata":{"id":"I1zr7rV8d2Oa"},"source":["> It is noted that as of Python 3.7, dictionary items maintain the order in which they are inserted into the dictionary. However, `dictionaries` are considered unordered collections and do not write code that depends on the order of the key–value pairs. "]},{"attachments":{},"cell_type":"markdown","metadata":{"id":"tB2j7j3YmpRZ"},"source":["As an example, we’ll build a dictionary that maps from subjects to grades, so the keys are `string` while the values are `integers`. The function `dict` creates a new dictionary with no items. "]},{"cell_type":"code","execution_count":1,"metadata":{"id":"TXcMt4SuqC7c","outputId":"4e36c533-c3db-49af-9752-4d54784fd757"},"outputs":[{"data":{"text/plain":["dict"]},"execution_count":1,"metadata":{},"output_type":"execute_result"}],"source":["type({}) # {} also treated as dict in Python"]},{"cell_type":"code","execution_count":2,"metadata":{"id":"JKYIUUsujPRj","outputId":"c01e40ca-ed2f-499c-c90d-2067bf773ff3"},"outputs":[{"data":{"text/plain":["(dict, {})"]},"execution_count":2,"metadata":{},"output_type":"execute_result"}],"source":["grade = dict()\n","type(grade), grade"]},{"attachments":{},"cell_type":"markdown","metadata":{"id":"M3f_fuvfm7SD"},"source":["To add/update items to the dictionary, you can again use subscript operator (square brackets):"]},{"cell_type":"code","execution_count":3,"metadata":{"id":"Crr5iMsmm7j6","outputId":"45ce7108-a32b-4011-f494-09e9343d103c"},"outputs":[{"name":"stdout","output_type":"stream","text":["{'calculus': 85}\n"]}],"source":["grade['calculus'] = 85 # Key:'calculus', value: 85\n","print(grade) # Note that key and value are separate by colon"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["You can create a `dictionary` that contains multiple items by enclosing in curly braces, `{}`, a comma-separated list of key–value pairs, each of the form `key:value`."]},{"cell_type":"code","execution_count":4,"metadata":{"id":"PpP_327sn4Xn","outputId":"e0759b62-0c2b-47fd-91ad-1c4c97002f61"},"outputs":[{"data":{"text/plain":["{'calculus': 85,\n"," 'introduction to mathematics': 80,\n"," 'computer programming': 90,\n"," 'linear algebra': 95}"]},"execution_count":4,"metadata":{},"output_type":"execute_result"}],"source":["grade = {'calculus':85, 'introduction to mathematics':80, 'computer programming':90, 'linear algebra':95}\n","grade"]},{"attachments":{},"cell_type":"markdown","metadata":{"id":"D2qbNFSAnt5Z"},"source":["You can store them using separate `lists` for subjects and scores, but the following update and maintenance will become tedious:\n","\n","```python\n","subjects = ['calculus', 'introduction to mathematics', 'computer programming', 'linear algebra']\n","score = [85, 80, 90, 95]\n","````"]},{"cell_type":"markdown","metadata":{"id":"QX4Ti3yEod_A"},"source":["You can now use the keys to look up the corresponding values:"]},{"cell_type":"code","execution_count":5,"metadata":{"id":"mo31IN5toMnq","outputId":"68d0338b-1aa9-4519-a341-ff64274e60de"},"outputs":[{"name":"stdout","output_type":"stream","text":["90\n"]}],"source":["print(grade['computer programming'])"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["You can obtain the number of items using `len()`"]},{"cell_type":"code","execution_count":6,"metadata":{},"outputs":[{"data":{"text/plain":["4"]},"execution_count":6,"metadata":{},"output_type":"execute_result"}],"source":["len(grade)"]},{"attachments":{},"cell_type":"markdown","metadata":{"id":"GzwHWKMpSnRP"},"source":["> Note that you can't access items in them using integer indexes like `grade[0]` because it is unordered collections. (Consider the case when you use 4, 2, 1, 0 as the keys). Therefore, you can't use slice syntax for dictionaries. "]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Trying to access a key that does not exist in a `dictionary` will result in a `KeyError` error message, much like a `list’s` “out-of-range” `IndexError` error message."]},{"cell_type":"code","execution_count":7,"metadata":{},"outputs":[{"ename":"KeyError","evalue":"'English'","output_type":"error","traceback":["\u001b[1;31m---------------------------------------------------------------------------\u001b[0m","\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)","\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_27052\\3219575328.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mgrade\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'English'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m","\u001b[1;31mKeyError\u001b[0m: 'English'"]}],"source":["grade['English']"]},{"cell_type":"markdown","metadata":{"id":"biss6VA0qehV"},"source":["To add or delete an entry, it is similar to list"]},{"cell_type":"code","execution_count":10,"metadata":{"id":"eI4RAkSFqlPM","outputId":"b16c9cee-3dcd-4f15-bdc1-5b2e463da9ea"},"outputs":[{"data":{"text/plain":["{'calculus': 85,\n"," 'introduction to mathematics': 80,\n"," 'computer programming': 90,\n"," 'linear algebra': 95,\n"," 'English': 100}"]},"execution_count":10,"metadata":{},"output_type":"execute_result"}],"source":["grade['English'] = 100\n","grade"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["You can delete a key–value pair from a dictionary with the `del` statement:"]},{"cell_type":"code","execution_count":11,"metadata":{"id":"qom8rf_zqq9O","outputId":"fe8364d6-7007-4b7f-ea91-25a64fb92d0e"},"outputs":[{"data":{"text/plain":["{'calculus': 85,\n"," 'introduction to mathematics': 80,\n"," 'computer programming': 90,\n"," 'linear algebra': 95}"]},"execution_count":11,"metadata":{},"output_type":"execute_result"}],"source":["del grade['English']\n","grade"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### The `keys()`, `values()`, and `items()` Methods"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["There are three `dictionary` methods that will return `list`-like values of the `dictionary`’s keys, values, or both keys and values: `keys()`, `values()`, and `items()`. The values returned by these methods are not true lists, but these data types (`dict_keys`, `dict_values`, and `dict_items`, respectively) can be used in `for` loops (Just like `range` object)!"]},{"cell_type":"markdown","metadata":{},"source":["If you want a true list from one of these methods, pass its list-like return value to the `list()` function"]},{"cell_type":"code","execution_count":15,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["['calculus', 'introduction to mathematics', 'computer programming', 'linear algebra']\n","[85, 80, 90, 95]\n"]}],"source":["subject = list(grade.keys())\n","score = list(grade.values())\n","print(subject)\n","print(score)"]},{"cell_type":"code","execution_count":12,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["85\n","80\n","90\n","95\n"]}],"source":["for v in grade.values():\n"," print(v)"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Here, a `for` loop iterates over each of the values in the `grade` dictionary. A `for` loop can also iterate over the keys:"]},{"cell_type":"code","execution_count":13,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["calculus\n","introduction to mathematics\n","computer programming\n","linear algebra\n"]}],"source":["for k in grade.keys():\n"," print(k)"]},{"cell_type":"code","execution_count":14,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["calculus\n","introduction to mathematics\n","computer programming\n","linear algebra\n"]}],"source":["for k in grade:\n"," print(k)"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["> Note that by default, it will traverse over the keys!"]},{"attachments":{},"cell_type":"markdown","metadata":{"id":"_bWKfSrwsber"},"source":["Dictionaries have a method called `items()` that returns a list of tuples, where each tuple is a key-value pair:"]},{"cell_type":"code","execution_count":16,"metadata":{"id":"nqNW-NBbsO8A","outputId":"d8c558c5-3c81-40e3-82c0-f1aa5bf556d9"},"outputs":[{"data":{"text/plain":["[('calculus', 85),\n"," ('introduction to mathematics', 80),\n"," ('computer programming', 90),\n"," ('linear algebra', 95)]"]},"execution_count":16,"metadata":{},"output_type":"execute_result"}],"source":["list(grade.items())"]},{"attachments":{},"cell_type":"markdown","metadata":{"id":"uXNIm4G4szJG"},"source":["Combining `items()`, multiple assignment, and `for`, you can see a nice code pattern for traversing the keys and values of a dictionary in a single loop:"]},{"cell_type":"code","execution_count":17,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["calculus 85\n","introduction to mathematics 80\n","computer programming 90\n","linear algebra 95\n"]}],"source":["for key, val in grade.items():\n"," print(key,val)"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["#### Checking Whether a Key or Value Exists in a Dictionary"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Recall from the previous chapter that the `in` and `not in` operators can check whether a value exists in a list. You can also use these operators to see whether a certain key or value exists in a dictionary"]},{"cell_type":"code","execution_count":13,"metadata":{"id":"kmCBCvvpokWE","outputId":"fc195640-1b73-4517-8dbe-ea833573379a"},"outputs":[{"data":{"text/plain":["(True, False, True)"]},"execution_count":13,"metadata":{},"output_type":"execute_result"}],"source":["'calculus' in grade, 'English' in grade.keys(), 85 in grade.values() "]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["> Again, it will check keys by default. Therefore, in the previous example, `'calculus' in grade` is essentially a shorter version of writing `'calculus' in grade.keys()`. This is always the case: if you ever want to check whether a value is (or isn’t) a key in the `dictionary`, you can simply use the `in` (or `not in`) keyword with the `dictionary` itself."]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["#### Retrieve value uisng `get()` Method"]},{"cell_type":"code","execution_count":24,"metadata":{},"outputs":[],"source":["if 'English' in grade:\n"," e_score= grade['English']"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["It’s tedious to check whether a key exists in a `dictionary` before accessing that key’s value. Fortunately, dictionaries have a `get()` method that takes two arguments: the key of the value to retrieve and a fallback value to return if that key does not exist."]},{"cell_type":"code","execution_count":21,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["I am bringing 2 cups.\n","I am bringing 0 eggs.\n"]}],"source":["picnicItems = {'apples': 5, 'cups': 2}\n","print('I am bringing ' + str(picnicItems.get('cups', 0)) + ' cups.') \n","print('I am bringing ' + str(picnicItems.get('eggs', 0)) + ' eggs.')"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Because there is no 'eggs' key in the `picnicItems` dictionary, the default value 0 is returned by the `get()` method. Without using `get()`, the code would have caused a `KeyError` message"]},{"cell_type":"code","execution_count":18,"metadata":{},"outputs":[{"ename":"KeyError","evalue":"'eggs'","output_type":"error","traceback":["\u001b[1;31m---------------------------------------------------------------------------\u001b[0m","\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)","\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_27052\\2486019301.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mpicnicItems\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m{\u001b[0m\u001b[1;34m'apples'\u001b[0m\u001b[1;33m:\u001b[0m \u001b[1;36m5\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'cups'\u001b[0m\u001b[1;33m:\u001b[0m \u001b[1;36m2\u001b[0m\u001b[1;33m}\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[1;34m'I am bringing '\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mstr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mpicnicItems\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'eggs'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;34m' eggs.'\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m","\u001b[1;31mKeyError\u001b[0m: 'eggs'"]}],"source":["picnicItems = {'apples': 5, 'cups': 2}\n","'I am bringing ' + str(picnicItems['eggs']) + ' eggs.'"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["#### Update value using `setdefault()` Method"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["You’ll often have to set a value in a `dictionary` for a certain key only if that key does not already have a value. The code looks something like this:"]},{"cell_type":"code","execution_count":30,"metadata":{},"outputs":[],"source":["spam = {'name': 'Pooka', 'age': 5}\n","if 'color' not in spam:\n"," spam['color'] = 'black'"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["The `setdefault()` method offers a way to do this in one line of code. The first argument passed to the method is the key to check for, and the second argument is the value to set at that key if the key does not exist."]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["The `setdefault()` method is a nice shortcut to ensure that a key exists. Here is a short program that counts the number of occurrences of each letter in a `string`."]},{"cell_type":"code","execution_count":36,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["{'I': 1, 't': 6, ' ': 13, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 5, 'i': 6, 'g': 2, 'h': 3, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 4, 'A': 1, 'p': 1, ',': 1, 'e': 5, 'k': 2, '.': 1}\n"]}],"source":["message = 'It was a bright cold day in April, and the clocks were striking thirteen.'\n","count = {}\n","\n","for character in message:\n"," if character not in count:\n"," count[character] = 0\n"," count[character] = count[character] + 1\n","\n","print(count) "]},{"cell_type":"code","execution_count":23,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["{'I': 1, 't': 6, ' ': 13, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 5, 'i': 6, 'g': 2, 'h': 3, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 4, 'A': 1, 'p': 1, ',': 1, 'e': 5, 'k': 2, '.': 1}\n"]}],"source":["message = 'It was a bright cold day in April, and the clocks were striking thirteen.'\n","count = {}\n","\n","for character in message:\n"," count.setdefault(character, 0)\n"," count[character] = count[character] + 1\n","\n","print(count) "]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["You can view the execution of this program at https://autbor.com/setdefault. The program loops over each character in the `message` variable’s string, counting how often each character appears. The `setdefault()` method ensures that the key is in the `count` `dictionary` (with a default value of 0) so the program doesn’t throw a `KeyError` error when `count[character] = count[character] + 1` is executed!"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["From the output, you can see that the lowercase letter c appears 3 times, the space character appears 13 times, and the uppercase letter A appears 1 time."]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### Pretty Printing"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["If you import the `pprint` module into your programs, you’ll have access to the `pprint()` function that will “pretty print” a `dictionary`’s values. This is helpful when you want a cleaner display of the items in a `dictionary` than what `print()` provides."]},{"cell_type":"code","execution_count":37,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["{' ': 13,\n"," ',': 1,\n"," '.': 1,\n"," 'A': 1,\n"," 'I': 1,\n"," 'a': 4,\n"," 'b': 1,\n"," 'c': 3,\n"," 'd': 3,\n"," 'e': 5,\n"," 'g': 2,\n"," 'h': 3,\n"," 'i': 6,\n"," 'k': 2,\n"," 'l': 3,\n"," 'n': 4,\n"," 'o': 2,\n"," 'p': 1,\n"," 'r': 5,\n"," 's': 3,\n"," 't': 6,\n"," 'w': 2,\n"," 'y': 1}\n"]}],"source":["import pprint\n","\n","message = 'It was a bright cold day in April, and the clocks were striking thirteen.'\n","count = {}\n","\n","for character in message:\n"," count.setdefault(character, 0)\n"," count[character] = count[character] + 1\n","\n","pprint.pprint(count)"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["You can view the execution of this program at https://autbor.com/pprint/. This time, when the program is run, the output looks much cleaner, ***with the keys sorted***. The `pprint.pprint()` function is especially helpful when the dictionary itself contains nested `lists` or `dictionaries`."]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["#### Dictionary Comprehensions"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Dictionary comprehensions provide a convenient notation for quickly generating `dictionaries`, often by mapping one `dictionary` to another. For example, in a `dictionary` with unique values, you can reverse the key–value pairs: "]},{"cell_type":"code","execution_count":38,"metadata":{},"outputs":[],"source":["months = {'January': 1, 'February': 2, 'March': 3}"]},{"cell_type":"code","execution_count":39,"metadata":{},"outputs":[{"data":{"text/plain":["{1: 'January', 2: 'February', 3: 'March'}"]},"execution_count":39,"metadata":{},"output_type":"execute_result"}],"source":["months2 = {number:name for name, number in months.items()}\n","months2"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Curly braces delimit a dictionary comprehension, and the expression to the left of the `for` specifies a key–value pair of the form `key:value`. The comprehension iterates through `months.items()`, unpacking each key–value pair tuple into the variables `name` and `number`. The expression `number:name` reverses the key and value, so the new dictionary maps the month numbers to the month names. \n","\n","A dictionary comprehension also can map a `dictionary`’s values to new values. The following comprehension converts a `dictionary` of names and `lists` of grades into a `dictionary` of names and grade-point averages. The variables `k` and `v` commonly mean key and value:"]},{"cell_type":"code","execution_count":40,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["{'Bob': [84, 95, 91], 'Sue': [98, 87, 94]}\n"]}],"source":["grades = {'Sue': [98, 87, 94], 'Bob': [84, 95, 91]}"]},{"cell_type":"code","execution_count":41,"metadata":{},"outputs":[{"data":{"text/plain":["{'Sue': 93.0, 'Bob': 90.0}"]},"execution_count":41,"metadata":{},"output_type":"execute_result"}],"source":["grades2 = {k:sum(v)/len(v) for k, v in grades.items()}\n","grades2"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["> Note the above is nested structure, with a `list` in a `dictionary`!"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### Using Data Structures to Model Real-World Things"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["A `tic-tac-toe` board looks like a large hash symbol (`#`) with nine slots that can each contain an `X`, an `O`, or a blank. To represent the board with a `dictionary`, you can assign each slot a key, as shown in below:\n","\n","
\n","\n","| 1 | 2 | 3 |\n","|---|---|---|\n","| 4 | 5 | 6 |\n","| 7 | 8 | 9 |\n","\n","
"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["You can use string values to represent what’s in each slot on the board: 'X', 'O', or ' ' (a space). Thus, you’ll need to store nine strings. You can use a dictionary of values for this. The string value with the key '3' can represent the top-right corner, the string value with the key '7' can represent the bottom-left corner, the string value with the key '5' can represent the middle, and so on. This dictionary is a data structure that represents a tic-tac-toe board. Store this board-as-a-dictionary in a variable named `board`."]},{"cell_type":"code","execution_count":41,"metadata":{},"outputs":[],"source":["board = {'1': ' ', '2': ' ', '3': ' ',\n"," '4': ' ', '5': ' ', '6': ' ',\n"," '7': ' ', '8': ' ', '9': ' '}"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["A board where player O has won by placing Os across the top might look like this:"]},{"cell_type":"code","execution_count":47,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["{'1': 'O', '2': 'O', '3': 'O', '4': 'X', '5': 'X', '6': ' ', '7': ' ', '8': ' ', '9': 'X'}\n"]}],"source":["board = {'1': 'O', '2': 'O', '3': 'O',\n"," '4': 'X', '5': 'X', '6': ' ',\n"," '7': ' ', '8': ' ', '9': 'X'}\n","print(board)"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["
\n","
source: https://automatetheboringstuff.com/2e/chapter5/
"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Of course, the player should see only what is printed to the screen, not the contents of variables. Let’s create a function to print the board dictionary onto the screen:"]},{"cell_type":"code","execution_count":48,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["O|O|O\n","-+-+-\n","X|X| \n","-+-+-\n"," | |X\n"]}],"source":["def printBoard(board):\n"," \"\"\"\n"," The function that prints out the board in a square shape\n"," \"\"\"\n"," print(board['1'] + '|' + board['2'] + '|' + board['3'])\n"," print('-+-+-')\n"," print(board['4'] + '|' + board['5'] + '|' + board['6'])\n"," print('-+-+-')\n"," print(board['7'] + '|' + board['8'] + '|' + board['9'])\n","\n","printBoard(board)"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["The `printBoard()` function can handle any tic-tac-toe data structure you pass it!"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Now let’s add code that allows the players to enter their moves."]},{"cell_type":"code","execution_count":49,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["O| | \n","-+-+-\n"," | | \n","-+-+-\n"," | | \n","O| | \n","-+-+-\n"," |X| \n","-+-+-\n"," | | \n"]}],"source":["board = {'1': ' ', '2': ' ', '3': ' ',\n"," '4': ' ', '5': ' ', '6': ' ',\n"," '7': ' ', '8': ' ', '9': ' '}\n","\n","board['1'] = 'O' # Update the board\n","printBoard(board)\n","board['5'] = 'X' \n","printBoard(board)"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["We can also check whether player has won the game or not using the following code:"]},{"cell_type":"code","execution_count":50,"metadata":{},"outputs":[{"data":{"text/plain":["False"]},"execution_count":50,"metadata":{},"output_type":"execute_result"}],"source":["p = 'O' # Check whether 'O' has won the game or not\n","\n","((board['1'] == board['2'] == board['3'] == p) or # Across top\n","(board['4'] == board['5'] == board['6'] == p) or # Across middle\n","(board['7'] == board['8'] == board['9'] == p) or # Across boardottom\n","(board['1'] == board['4'] == board['7'] == p) or # Down left\n","(board['2'] == board['5'] == board['8'] == p) or # Down middle\n","(board['3'] == board['6'] == board['9'] == p) or # Down right\n","(board['3'] == board['5'] == board['7'] == p) or # Diagonal\n","(board['1'] == board['5'] == board['9'] == p)) # Diagonal"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["> Note that by enclosing the condiations with `()`, we do not have to add `\\` for multipline commands."]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### > Exercise 1: Tic-tac-toe is a classic pencil-and-paper game played on a 3 × 3 grid. Players take turns placing their 'X' or 'O' marks, trying to get three in a row. Try to complete the following game design by complete three functions `getBlankBoard()`, `isValidSpace()` and `isBoardFull()`."]},{"cell_type":"code","execution_count":2,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["Overwriting ttt.py\n"]}],"source":["%%writefile ttt.py\n","\n","def printBoard(board):\n"," \"\"\"\n"," The function that prints out the board in a square shape\n"," \"\"\"\n"," print(board['1'] + '|' + board['2'] + '|' + board['3'])\n"," print('-+-+-')\n"," print(board['4'] + '|' + board['5'] + '|' + board['6'])\n"," print('-+-+-')\n"," print(board['7'] + '|' + board['8'] + '|' + board['9'])\n","\n","\n","def updateBoard(board, space, mark):\n"," \"\"\"Sets the space on the board to mark.\"\"\"\n"," board[space] = mark\n","\n","def isWinner(board, player):\n"," \"\"\"Return True if player is a winner on this TTTBoard.\"\"\"\n"," # Shorter variable names used here for readablility:\n"," b, p = board, player\n"," # Check for 3 marks across 3 rows, 3 columns, and 2 diagonals.\n"," return ((b['1'] == b['2'] == b['3'] == p) or # Across top\n"," (b['4'] == b['5'] == b['6'] == p) or # Across middle\n"," (b['7'] == b['8'] == b['9'] == p) or # Across bottom\n"," (b['1'] == b['4'] == b['7'] == p) or # Down left\n"," (b['2'] == b['5'] == b['8'] == p) or # Down middle\n"," (b['3'] == b['6'] == b['9'] == p) or # Down right\n"," (b['3'] == b['5'] == b['7'] == p) or # Diagonal\n"," (b['1'] == b['5'] == b['9'] == p)) # Diagonal\n","\n","def getBlankBoard():\n"," \"\"\"Create a new, blank tic-tac-toe board.\"\"\"\n"," # Map of space numbers: 1|2|3\n"," # -+-+-\n"," # 4|5|6\n"," # -+-+-\n"," # 7|8|9\n"," # Keys are '1' through '9', the values are 'X', 'O', or ' ':\n"," # Initialize all spaces of the board as blank string ' ' using loop or dictionary complehention\n"," ALL_SPACES = ['1', '2', '3', '4', '5', '6', '7', '8', '9']\n"," ______________________________\n"," return board\n","\n","def isValidSpace(board, space):\n"," \"\"\"Returns True if the space on the board is a valid space number (1-9)\n"," and the space is blank.\"\"\"\n"," ALL_SPACES = ['1', '2', '3', '4', '5', '6', '7', '8', '9']\n"," return ____________ and ________________\n","\n","def isBoardFull(board):\n"," \"\"\"Return True if every space on the board has been taken.\"\"\"\n"," for v in ________: # Traverse over the board to see if there is blank space\n"," if v == ' ':\n"," return False # If any space is blank, return False.\n"," return True # No spaces are blank, so return True\n","\n","\n","\n","# The logic of the game\n","print('Welcome to Tic-Tac-Toe!')\n","gameBoard = getBlankBoard() # Create a TTT board dictionary.\n","currentPlayer, nextPlayer = 'X', 'O' # X goes first, O goes next.\n","\n","while True: # Main game loop.\n","\t# 1. Display the board on the screen:\n","\tprintBoard(gameBoard)\n","\n","\t# 2. Keep asking the player until they enter a number 1-9:\n","\tmove = None\n","\twhile not isValidSpace(gameBoard, move):\n","\t\tprint('What is ' + currentPlayer + '\\'s move? (1-9)')\n","\t\tmove = input('> ')\n","\tupdateBoard(gameBoard, move, currentPlayer) # Make the move.\n","\n","\t# 3. Check if the game is over:\n","\tif isWinner(gameBoard, currentPlayer): # Check for a winner.\n","\t\tprintBoard(gameBoard)\n","\t\tprint(currentPlayer + ' has won the game!')\n","\t\tbreak\n","\telif isBoardFull(gameBoard): # Check for a tie.\n","\t\tprint(printBoard(gameBoard))\n","\t\tprint('The game is a tie!')\n","\t\tbreak\n","\t# 4. Switch turns to the next player using multiple assignment:\n","\tcurrentPlayer, nextPlayer = nextPlayer, currentPlayer\n","print('Thanks for playing!')"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### Nested Dictionaries and Lists"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["#### A List of Dictionaries"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Consider a game featuring aliens that can have different colors and point values. This simple `dictionary` stores information about a particular alien:"]},{"cell_type":"code","execution_count":42,"metadata":{},"outputs":[],"source":["alien_0 = {'color': 'green', 'points': 5}"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["The `alien_0` dictionary contains a variety of information about one alien, but it has no room to store information about a second alien, much less a screen full of aliens. How can you manage a fleet of aliens? One way is to make a list of aliens in which each alien is a `dictionary` of information about that alien."]},{"cell_type":"code","execution_count":57,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["{'color': 'green', 'points': 5, 'speed': 'slow'}\n","{'color': 'green', 'points': 5, 'speed': 'slow'}\n","{'color': 'green', 'points': 5, 'speed': 'slow'}\n","{'color': 'green', 'points': 5, 'speed': 'slow'}\n","{'color': 'green', 'points': 5, 'speed': 'slow'}\n","...\n","Total number of aliens: 30\n"]}],"source":["aliens = []\n","# Make 30 green aliens.\n","for alien_number in range(30):\n"," new_alien = {'color': 'green', 'points': 5, 'speed': 'slow'}\n"," aliens.append(new_alien)\n","# Show the first 5 aliens.\n","for alien in aliens[:5]:\n"," print(alien)\n","print(\"...\")\n","# Show how many aliens have been created.\n","print(f\"Total number of aliens: {len(aliens)}\")"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["These aliens all have the same characteristics, but `Python` considers each one a separate object, which allows us to modify each alien individually. How might you work with a group of aliens like this? Imagine that one aspect of a game has some aliens changing color and moving faster as the game progresses. When it’s time to change colors, we can use a `for` loop and an `if` statement to change the color of the aliens. For example, to change the first three aliens to yellow, medium-speed aliens worth 10 points each, we could do this:"]},{"cell_type":"code","execution_count":58,"metadata":{},"outputs":[{"data":{"text/plain":["[{'color': 'yellow', 'points': 10, 'speed': 'medium'},\n"," {'color': 'yellow', 'points': 10, 'speed': 'medium'},\n"," {'color': 'yellow', 'points': 10, 'speed': 'medium'},\n"," {'color': 'green', 'points': 5, 'speed': 'slow'},\n"," {'color': 'green', 'points': 5, 'speed': 'slow'},\n"," {'color': 'green', 'points': 5, 'speed': 'slow'},\n"," {'color': 'green', 'points': 5, 'speed': 'slow'},\n"," {'color': 'green', 'points': 5, 'speed': 'slow'},\n"," {'color': 'green', 'points': 5, 'speed': 'slow'},\n"," {'color': 'green', 'points': 5, 'speed': 'slow'}]"]},"execution_count":58,"metadata":{},"output_type":"execute_result"}],"source":["for alien in aliens[:3]:\n"," if alien['color'] == 'green':\n"," alien['color'] = 'yellow'\n"," alien['speed'] = 'medium'\n"," alien['points'] = 10\n","\n","aliens[:10]"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["## Sets"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["A `set` is an unordered collection of unique values. `Sets` may contain only immutable objects, like `strings`, `ints`, `floats` and `tuples` that contain only immutable elements. "]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["The following code creates a `set` of strings named `colors`: "]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[{"data":{"text/plain":["{'blue', 'green', 'orange', 'red', 'yellow'}"]},"execution_count":1,"metadata":{},"output_type":"execute_result"}],"source":["colors = {'red', 'orange', 'yellow', 'green', 'red', 'blue'} # Similar to set in math\n","colors"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Notice that the duplicate string `'red'` was ignored (without causing an error). An important use of `sets` is ***duplicate elimination***, which is automatic when creating a `set`. Also, the resulting `set’s` values may not be displayed in the same order as they were listed! Though the color names are displayed in sorted order, ***sets are unordered***. You should not write code that depends on the order of their elements!\n","\n","> Note that we also use curly bracket to create a set!"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Though `sets` are iterable, they are not sequences and do not support indexing and slicing with square brackets, `[]`."]},{"cell_type":"code","execution_count":2,"metadata":{},"outputs":[{"ename":"TypeError","evalue":"'set' object is not subscriptable","output_type":"error","traceback":["\u001b[1;31m---------------------------------------------------------------------------\u001b[0m","\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)","\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_28268\\4110793329.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mcolors\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m","\u001b[1;31mTypeError\u001b[0m: 'set' object is not subscriptable"]}],"source":["colors[0]"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["You can determine the number of items in a set with the built-in `len()` function: "]},{"cell_type":"code","execution_count":3,"metadata":{},"outputs":[{"data":{"text/plain":["5"]},"execution_count":3,"metadata":{},"output_type":"execute_result"}],"source":["len(colors)"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["You can check whether a `set` contains a particular value using the `in` and `not in` operators:"]},{"cell_type":"code","execution_count":4,"metadata":{},"outputs":[{"data":{"text/plain":["(True, True)"]},"execution_count":4,"metadata":{},"output_type":"execute_result"}],"source":["'red' in colors, 'purple' not in colors"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["`Sets` are iterable, so you can process each set element with a `for` loop:"]},{"cell_type":"code","execution_count":6,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["green blue red yellow orange "]}],"source":["for color in colors: # {'blue', 'green', 'orange', 'red', 'yellow'}\n"," print(color, end=' ')"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["`Sets` are unordered, so there’s no significance to the iteration order!"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### Creating a `Set` with the Built-In `set()` Function"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["You can create a `set` from another collection of values by using the built-in `set()` function — here we create a `list` that contains several duplicate integer values and use that `list` as `set`’s argument:"]},{"cell_type":"code","execution_count":7,"metadata":{},"outputs":[{"data":{"text/plain":["[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4]"]},"execution_count":7,"metadata":{},"output_type":"execute_result"}],"source":["numbers = list(range(10)) + list(range(5))\n","numbers"]},{"cell_type":"code","execution_count":8,"metadata":{},"outputs":[{"data":{"text/plain":["{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}"]},"execution_count":8,"metadata":{},"output_type":"execute_result"}],"source":["set(numbers)"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["If you need to create an empty `set`, you must use the `set()` function with empty parentheses, rather than empty braces, `{}`, which represent an empty `dictionary`:"]},{"cell_type":"code","execution_count":9,"metadata":{},"outputs":[{"data":{"text/plain":["set()"]},"execution_count":9,"metadata":{},"output_type":"execute_result"}],"source":["set()"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["> Python displays an empty `set` as `set()` to avoid confusion with Python’s string representation of an empty `dictionary` (`{}`)."]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### `Set` Operators and Methods"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["`Sets` are mutable — you can add and remove elements, but set elements must be immutable. Therefore, a `set` cannot have other `sets` as elements."]},{"cell_type":"code","execution_count":10,"metadata":{},"outputs":[{"data":{"text/plain":["{5, 6, 'a'}"]},"execution_count":10,"metadata":{},"output_type":"execute_result"}],"source":["{6,5,'a'}"]},{"cell_type":"code","execution_count":11,"metadata":{},"outputs":[{"ename":"TypeError","evalue":"unhashable type: 'set'","output_type":"error","traceback":["\u001b[1;31m---------------------------------------------------------------------------\u001b[0m","\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)","\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_28268\\916909930.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;33m{\u001b[0m\u001b[1;36m7\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m3\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m{\u001b[0m\u001b[1;36m3\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m5\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m7\u001b[0m\u001b[1;33m}\u001b[0m\u001b[1;33m}\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m","\u001b[1;31mTypeError\u001b[0m: unhashable type: 'set'"]}],"source":["{7,3,{3,5,7}}"]},{"cell_type":"code","execution_count":12,"metadata":{},"outputs":[{"ename":"TypeError","evalue":"unhashable type: 'list'","output_type":"error","traceback":["\u001b[1;31m---------------------------------------------------------------------------\u001b[0m","\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)","\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_28268\\731837709.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;33m{\u001b[0m\u001b[1;36m7\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m3\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m3\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m5\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m7\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m}\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m","\u001b[1;31mTypeError\u001b[0m: unhashable type: 'list'"]}],"source":["{7,3,[3,5,7]}"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["#### Methods for Adding and Removing Elements"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":[" Here we first discuss operators and methods that modify an existing `set`. "]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Set method `update()` performs a union operation modifying the set in-place — the argument can be any iterable:"]},{"cell_type":"code","execution_count":13,"metadata":{},"outputs":[{"data":{"text/plain":["{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}"]},"execution_count":13,"metadata":{},"output_type":"execute_result"}],"source":["numbers = {1, 3, 5} \n","numbers.update(range(10)) \n","numbers"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["`Set` method `add()` inserts its argument if the argument is not already in the set; otherwise, the\n","`set` remains unchanged:"]},{"cell_type":"code","execution_count":14,"metadata":{},"outputs":[{"data":{"text/plain":["{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 17}"]},"execution_count":14,"metadata":{},"output_type":"execute_result"}],"source":["numbers.add(17)\n","numbers.add(3)\n","numbers"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["`Set` method `remove()` removes its argument from the `set` — a `KeyError` occurs if the value is not in the `set`:"]},{"cell_type":"code","execution_count":15,"metadata":{},"outputs":[{"data":{"text/plain":["{0, 1, 2, 4, 5, 6, 7, 8, 9, 17}"]},"execution_count":15,"metadata":{},"output_type":"execute_result"}],"source":["numbers.remove(3)\n","numbers"]},{"cell_type":"code","execution_count":16,"metadata":{},"outputs":[{"ename":"KeyError","evalue":"11","output_type":"error","traceback":["\u001b[1;31m---------------------------------------------------------------------------\u001b[0m","\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)","\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_28268\\550142172.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mnumbers\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mremove\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m11\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m","\u001b[1;31mKeyError\u001b[0m: 11"]}],"source":["numbers.remove(11)"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Method `discard()` also removes its argument from the `set` but does not cause an exception if the value is not in the `set`. "]},{"cell_type":"code","execution_count":18,"metadata":{},"outputs":[{"data":{"text/plain":["{2, 4, 5, 6, 7, 8, 9, 17}"]},"execution_count":18,"metadata":{},"output_type":"execute_result"}],"source":["numbers.discard(1)\n","numbers"]},{"cell_type":"code","execution_count":19,"metadata":{},"outputs":[],"source":["numbers.discard(0)"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### Mathematical Set Operations"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["The operators and methods presented in this section each result in a new set!"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["#### Union "]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["The union of two `sets` is a set consisting of all the unique elements from both sets. You can calculate the union with the `|` operator or with the set `union()` method:"]},{"cell_type":"code","execution_count":20,"metadata":{},"outputs":[{"data":{"text/plain":["{1, 2, 3, 4, 5}"]},"execution_count":20,"metadata":{},"output_type":"execute_result"}],"source":["{1, 3, 5} | {2, 3, 4}"]},{"cell_type":"code","execution_count":70,"metadata":{},"outputs":[{"data":{"text/plain":["{1, 3, 5, 20, 40}"]},"execution_count":70,"metadata":{},"output_type":"execute_result"}],"source":["{1, 3, 5}.union([20, 20, 3, 40, 40])"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["The operands of the binary set operators, like `|`, must both be `sets`. The corresponding `set` methods may receive any iterable object as an argument — we passed a `list`. **When a mathematical `set` method receives a non-set iterable argument, it first converts the iterable to a set, then applies the mathematical operation.** "]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["#### Intersection "]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["The intersection of two `sets` is a set consisting of all the unique elements that the two `sets` have in common. You can calculate the intersection with the `&` operator or with the set `intersection()` method:"]},{"cell_type":"code","execution_count":21,"metadata":{},"outputs":[{"data":{"text/plain":["{3}"]},"execution_count":21,"metadata":{},"output_type":"execute_result"}],"source":["{1, 3, 5} & {2, 3, 4}"]},{"cell_type":"code","execution_count":22,"metadata":{},"outputs":[{"data":{"text/plain":["{1, 3}"]},"execution_count":22,"metadata":{},"output_type":"execute_result"}],"source":["{1, 3, 5}.intersection([1, 2, 2, 3, 3, 4, 4])"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["#### Difference "]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["The difference between two `sets` is a set consisting of the elements in the left operand that are not in the right operand. You can calculate the difference with the `-` operator or with the set `difference()` method:"]},{"cell_type":"code","execution_count":23,"metadata":{},"outputs":[{"data":{"text/plain":["{1, 5}"]},"execution_count":23,"metadata":{},"output_type":"execute_result"}],"source":["{1, 3, 5} - {2, 3, 4}"]},{"cell_type":"code","execution_count":24,"metadata":{},"outputs":[{"data":{"text/plain":["{1, 5, 7}"]},"execution_count":24,"metadata":{},"output_type":"execute_result"}],"source":["{1, 3, 5, 7}.difference([2, 2, 3, 3, 4, 4])"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["#### Symmetric Difference "]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["The symmetric difference between two sets is a set consisting of the elements of both sets that are ***not in common with one another***. You can calculate the symmetric difference with the `^` operator or with the set `symmetric_difference` method:"]},{"cell_type":"code","execution_count":25,"metadata":{},"outputs":[{"data":{"text/plain":["{1, 2, 4, 5}"]},"execution_count":25,"metadata":{},"output_type":"execute_result"}],"source":["{1, 3, 5} ^ {2, 3, 4}"]},{"cell_type":"code","execution_count":26,"metadata":{},"outputs":[{"data":{"text/plain":["{1, 2, 4, 5, 7}"]},"execution_count":26,"metadata":{},"output_type":"execute_result"}],"source":["{1, 3, 5, 7}.symmetric_difference([2, 2, 3, 3, 4, 4])"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["#### Disjoint"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Two `sets` are disjoint if they do not have any common elements. You can determine this with the set `isdisjoint()` method:"]},{"cell_type":"code","execution_count":27,"metadata":{},"outputs":[{"data":{"text/plain":["True"]},"execution_count":27,"metadata":{},"output_type":"execute_result"}],"source":["{1, 3, 5}.isdisjoint({2, 4, 6})"]},{"cell_type":"code","execution_count":28,"metadata":{},"outputs":[{"data":{"text/plain":["False"]},"execution_count":28,"metadata":{},"output_type":"execute_result"}],"source":["{1, 3, 5}.isdisjoint({4, 6, 1})"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### Set Comprehensions"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Like dictionary comprehensions, you define set comprehensions in curly braces. Let’s create a new `set` containing only the unique even values in the `list` numbers:"]},{"cell_type":"code","execution_count":29,"metadata":{},"outputs":[{"data":{"text/plain":["{2, 4, 6, 8, 10}"]},"execution_count":29,"metadata":{},"output_type":"execute_result"}],"source":["numbers = [1, 2, 2, 3, 4, 5, 6, 6, 7, 8, 9, 10, 10]\n","evens = {item for item in numbers if item % 2 == 0}\n","\n","evens"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### Sorting the `set` and `dictionary` "]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["As we mentioned last week, data types like `tuples` don’t provide methods like `sort()`. However `Python` provides the built-in function `sorted()`, which takes any sequence as a parameter and returns a new container with the same elements in a different order. You can also apply `sorted` to the set, but the returning container will be `list`."]},{"cell_type":"code","execution_count":26,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["Help on built-in function sorted in module builtins:\n","\n","sorted(iterable, /, *, key=None, reverse=False)\n"," Return a new list containing all items from the iterable in ascending order.\n"," \n"," A custom key function can be supplied to customize the sort order, and the\n"," reverse flag can be set to request the result in descending order.\n","\n"]}],"source":["help(sorted)"]},{"cell_type":"code","execution_count":35,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["['2', '4', '7', 'A', 'Q']\n","['A', '2', '4', '7', 'Q']\n"]}],"source":["RANKS = [\"A\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"J\", \"Q\", \"K\"]\n","\n","def rank_key(card):\n"," return RANKS.index(card)\n","\n","ori_set = {\"A\", \"2\", \"7\", \"4\", \"Q\"}\n","print(sorted(ori_set))\n","sorted_list = sorted(ori_set, key=rank_key) \n","# Each element will be replaced by the output of rank_key() and sorts!\n","print(sorted_list)"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["Note that we have changed the behavior of the `sorted()` function by providing the custom key that allows us to sort the data in a specific order using the predefined `list` and the `index()` function."]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["If you would like to sort the `dictionary`, you need to use the `items()` method (Otherwise, it will only return keys). The returning container will again be a `list`:"]},{"cell_type":"code","execution_count":34,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["[('calculus', 85), ('introduction to computer science', 90), ('introduction to mathematics', 80), ('linear algebra', 95)]\n"]}],"source":["grade = {'calculus':85, 'introduction to mathematics':80, 'introduction to computer science':90, 'linear algebra':95}\n","sorted_list = sorted(grade.items())\n","print(sorted_list)"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["If you would like to sort by the value, use the following code:"]},{"cell_type":"code","execution_count":36,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["[('introduction to mathematics', 80), ('calculus', 85), ('computer programming', 90), ('linear algebra', 95)]\n"]}],"source":["def value_key(x):\n"," return x[1]\n","\n","grade = {'calculus':85, 'introduction to mathematics':80, 'computer programming':90, 'linear algebra':95}\n","sorted_dict = sorted(grade.items(), key=value_key)\n","print(sorted_dict)"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["### > Exercise 2: Try to design a program that counts the number of unique characters in a string. Be sure to exclude the punctuation and white space and the character with upper and lower cases are treated as different characters. \n","\n","
\n","
source: https://realpython.com/python-encodings-guide/
"]},{"cell_type":"code","execution_count":37,"metadata":{},"outputs":[{"data":{"text/plain":["'!\"#$%&\\'()*+,-./:;<=>?@[\\\\]^_`{|}~'"]},"execution_count":37,"metadata":{},"output_type":"execute_result"}],"source":["import string\n","\n","# You can obtain all the punctuations using the following attribute\n","string.punctuation"]},{"cell_type":"code","execution_count":26,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["Number of unique characters: 27\n"]}],"source":["# Sample text\n","text = \"The quick brown fox jumped over the lazy dog. The dog didn't seem to mind!\"\n","\n","# Create a set of punctuation characters\n","punctuation = set(string.punctuation)\n"," \n","# Create a set of all characters included in the text\n","all_chars = _____________\n"," \n","# Find the difference between the two sets to get the non-punctuation characters\n","non_punctuation_chars = ____________________________\n","# Also remove the whitespace\n","_____________________________\n"," \n","# Count the number of non-punctuation characters\n","num_unique_chars = len(non_punctuation_chars)\n","\n","print(\"Number of unique characters:\", num_unique_chars)\n","\n","# Sanity check\n","assert num_unique_chars == 27"]},{"attachments":{},"cell_type":"markdown","metadata":{},"source":["In this chapter, we discussed Python’s `dictionary` and `set` collections. They are both unorder, mutable and do not allow duplicates.\n","\n","We said what a dictionary is and presented several examples. We showed the syntax of key–value pairs and showed how to use them to create `dictionaries` with comma-separated lists of key–value pairs in curly braces, `{}`. You also created dictionaries with dictionary comprehensions. You used square brackets, `[]`, to retrieve the value corresponding to a key, and to insert and update key–value pairs. You also used the dictionary method update to change a key’s associated value. You iterated through a dictionary’s keys, values and items.\n","\n","You created `sets` of unique immutable values. You combined `sets` with set operators and methods, changed sets’ values with the mutable set operations and created `sets` with set comprehensions. You saw that sets are mutable.\n","\n","A short comparison of the containers is shown below:\n","\n","\n","| Feature | List | Tuple | Dictionary | Set |\n","|------------------|---------|---------|-------------|-------------|\n","| Mutable | Yes | No | Yes (keys are immutable) | Yes |\n","| Iterable (Can be use in for loop) | Yes | Yes | Yes | Yes |\n","| Ordered (Can access by index, slicing) | Yes | Yes | No | No |\n","| Duplicate Values | Allowed | Allowed | Not in keys | Not allowed |"]},{"cell_type":"markdown","metadata":{},"source":[]}],"metadata":{"colab":{"collapsed_sections":["SwFKFBMwRzoa","n3ezAAdIsgpj","gASYx5-Cxzyg","2kLRVhae3rSa","DPpfFEA07W0A","uloOTsPL9A74","MTJO4K049nuU","3hD9uBt6AW9l","IvviPig3At12","HQK5zGP749m3","7YVyJ-IgBZ7s","L5VlI3VKg_dV","wgqoOGqEiUre","jscaE3K65HP9","UMo588t4rY-O","AGs4jgnSsZa1"],"provenance":[],"toc_visible":true},"kernelspec":{"display_name":"base","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.9.13"},"vscode":{"interpreter":{"hash":"1561eddc5e0c9c74df968f74d5080d02882967127f956e6e7049c43d2ef42321"}}},"nbformat":4,"nbformat_minor":0}